package com.songcha.sakura.download

import com.songcha.library_common.util.LogUtil
import com.songcha.library_common.util.ToastUtil
import com.songcha.sakura.download.base.DownloadDelegate
import com.songcha.sakura.download.base.DownloadOption
import com.songcha.sakura.download.base.DownloadTask
import com.songcha.sakura.download.base.TaskState
import com.songcha.sakura.download.m3u8.*
import com.songcha.sakura.helper.VideoHelper
import com.songcha.sakura.struct.VideoType
import com.songcha.sakura.util.FileUtil
import okhttp3.internal.notifyAll
import okhttp3.internal.wait
import java.io.File
import java.util.concurrent.ArrayBlockingQueue

//这里使用messenger通信，其实不用处理同步问题，但为了学习，还是进行处理
class DownloadManager  {

    companion object{

        //private var url:String=""

        //private var option:DownloadOption=DownloadOption()
        private val lock=Any()
        private val MAX_WAITQ_UEUE_COUNT=10
        private val MAX_DOWNLOADING_QUEUE_COUNT=3

        //任务列表
        private val taskList=mutableListOf<DownloadTask>()
        //等待队列
        private var waitQueue=ArrayBlockingQueue<DownloadTask>(MAX_WAITQ_UEUE_COUNT)
        //进行中队列
        private var downloadingQueue=ArrayBlockingQueue<DownloadTask>(MAX_DOWNLOADING_QUEUE_COUNT)

        //生产者线程
        private var waitProducerThread:Thread?=null

        @Volatile
        private var putTaskFlag=false

        //下载委托
        //private var downloadDelegate:DownloadDelegate?=null

        //下载线程
        private var threads=ArrayList<DownloadThread>()
        private var mListener:IDownloaderListener?=null
        private var putTask:DownloadTask?=null

        private var mTaskIdIncrease=0
        private var mMaxDownloadingWaitLock=Any()



        @JvmStatic
        fun setWaitQueueMaxSize(size:Int){
            waitQueue=ArrayBlockingQueue<DownloadTask>(size)
        }

        @JvmStatic
        fun setDownloadQueueMaxSize(size:Int){
            downloadingQueue=ArrayBlockingQueue<DownloadTask>(size)
        }


        @JvmStatic
        fun getTaskList():MutableList<DownloadTask>{
            return taskList
        }

        @JvmStatic
        fun generateTaskId():Int{
          return ++mTaskIdIncrease
        }

        /*fun init(option: DownloadOption){
            waitQueue=ArrayBlockingQueue<Task>(option.maxWaitQueueCount)
            downloadingQueue=ArrayBlockingQueue<Task>(option.maxDownloadTaskCount)
        }*/

        @JvmStatic
        fun setListener(listener: IDownloaderListener){
            this.mListener=listener
        }


        /*@JvmStatic
        fun getLocalTask(){
            val dataPath=DownloadConfig.getVideoDownloadPath()
            val dataFile = File(dataPath)
            val files = dataFile.listFiles()
            if(files==null) return
            val list= mutableListOf<DownloadTask>()
            for (file in files) {
                if (file.isDirectory) {

                    val comicPath=dataPath+"/"+file.name
                    val comicFile = File(comicPath)
                    //番剧存在
                    if(FileUtil.isDirExist(comicFile)){
                        //遍历集
                        val files2 = comicFile.listFiles()
                        if(files2==null) continue
                        for (file2 in files2) {
                            if(file2.name.endsWith(".m3u8.index")){
                                val m3u8Path=file2.absolutePath.substring(0,file2.absolutePath.length-".index".length)
                                val option = M3u8DownloadOption()
                                option.filePath = m3u8Path
                                option.setPath()

                                if(!File(option.episodePath).exists()) continue
                                val task= M3u8DownloadTask("",option)
                                //task.setPath()

                                task.option  as M3u8DownloadOption
                                task.option.urlConverter = M3u8UrlConverter()
                                task.option.tsConverter = M3u8TsConverter()

                                val arr=FileUtil.readContent(task.option.urlPath).split("|")
                                if(arr.size==0) continue
                                val url= arr[0]
                                task.url=url
                                val resolution=arr[2]
                                task.option.resolution=resolution
                                var currentTsCount=0
                                val files3 = File(task.option.episodePath).listFiles()
                                if(files3!=null){
                                    for(file3 in files3){
                                        if(file3.name.endsWith(".ts")){
                                            currentTsCount++
                                        }
                                    }
                                }

                                var totalTsCount=0
                                FileUtil.readContent(file2.absolutePath){ line->
                                    if(line.contains(".ts")){
                                        totalTsCount++
                                    }
                                }

                                task.downloadDelegate= DownloadDelegate(M3u8Downloader())

                                task.id=generateTaskId()
                                task.state=TaskState.PAUSE
                                //task.currentSize=currentTsCount
                                //task.fileSize=totalTsCount
                                task.currentTsCount=currentTsCount
                                task.totalTsCount=totalTsCount
                                task.setProgress()

                                list.add(task)

                            }

                        }
                    }

                }

            }

            if(list.size>0){
                taskList.clear()
                taskList.addAll(list)
                //EventBus.getDefault().postSticky(LocalTaskEvent(taskList))
            }

        }*/

        @JvmStatic
        fun getLocalTask(){
            val list= mutableListOf<DownloadTask>()

            VideoHelper.getLocalVideoList(object :VideoHelper.ILocalVideoListener{
                override fun onSearchComicBefore(comicFile: File) {

                }

                override fun onSearchComicAfter(comicFile: File) {

                }

                override fun onSearchEpisode(type: VideoType, comicFile: File, episodeFile: File) {
                    if (type==VideoType.UNKNOW && episodeFile.name.endsWith(".m3u8.index")) {
                        val m3u8Path = episodeFile.absolutePath.substring(
                            0,
                            episodeFile.absolutePath.length - ".index".length
                        )
                        val option = M3u8DownloadOption()
                        option.filePath = m3u8Path
                        option.setPath()

                        if (!File(option.episodePath).exists()) return
                        val task = M3u8DownloadTask("", option)
                        //task.setPath()

                        task.option as M3u8DownloadOption
                        task.option.urlConverter = M3u8UrlConverter()
                        task.option.tsConverter = M3u8TsConverter()

                        val arr = FileUtil.readContent(task.option.urlPath).split("|")
                        if (arr.size == 0) return
                        val url = arr[0]
                        task.url = url
                        val resolution = arr[2]
                        task.option.resolution = resolution
                        var currentTsCount = 0
                        val files3 = File(task.option.episodePath).listFiles()
                        if (files3 != null) {
                            for (file3 in files3) {
                                if (file3.name.endsWith(".ts")) {
                                    currentTsCount++
                                }
                            }
                        }

                        var totalTsCount = 0
                        FileUtil.readContent(episodeFile.absolutePath) { line ->
                            if (line.contains(".ts")) {
                                totalTsCount++
                            }
                        }

                        task.downloadDelegate = DownloadDelegate(M3u8Downloader())

                        task.id = generateTaskId()
                        task.state = TaskState.PAUSE
                        //task.currentSize=currentTsCount
                        //task.fileSize=totalTsCount
                        task.currentTsCount = currentTsCount
                        task.totalTsCount = totalTsCount
                        task.setProgress()

                        list.add(task)
                    }
                }

            })

            if(list.size>0){
                taskList.clear()
                taskList.addAll(list)
                //EventBus.getDefault().postSticky(LocalTaskEvent(taskList))
            }

        }


        @JvmStatic
        fun create(listener: IDownloaderListener, url:String, option: M3u8DownloadOption, downloadDelegate: DownloadDelegate):Int{

            if(this.mListener==null ){
                this.mListener=listener
            }

           /* if(this.downloadDelegate==null){
                this.downloadDelegate=downloadDelegate
            }*/

            return startTask(url,option,downloadDelegate)
        }

        @JvmStatic
        private fun startTask(url:String, option: DownloadOption, downloadDelegate: DownloadDelegate):Int{

            /*if(waitQueue.size+1>option.maxWaitQueueCount){
                ToastUtil.show("等待队列已满")
                return -2
            }*/


            /*   val idx=option.filePath.lastIndexOf("/")
               if(idx==-1) {
                   ToastUtil.show("无效文件路径")
                   return -3
               }*/
             var task:DownloadTask?=null
            if(option is M3u8DownloadOption){
                task= M3u8DownloadTask(url,option)
            }else{

            }

            if(task!=null){
                task.downloadDelegate=downloadDelegate
                return startByTask(task)
            }else{
                return -8
            }

        }

        @JvmStatic
        private fun startByTask(task:DownloadTask):Int{
            if(task is M3u8DownloadTask){
                if(task.downloadDelegate.validateUrl(task.url)){
                    ToastUtil.show("无效的下载地址")
                    return -7
                }
            }

            var taskIdx=-1
            synchronized(lock){
                taskIdx=isTaskExist(task)
                if(taskIdx>-1){
                    //val tmpTask=taskList[taskIdx]
                    if(task.state!=TaskState.PAUSE && task.state!=TaskState.ERROR){
                        ToastUtil.show("下载任务已存在")
                        return -1
                    }
                }

            }

            if(waitQueue.size>=MAX_WAITQ_UEUE_COUNT){
                ToastUtil.show("等待任务队列已满")
                return -5
            }

            var ret=0

            val thread= DownloadThread{

                ret=task.downloadDelegate.download(task, this.mListener!!,object: IDownloadManager {
                    override fun putTask(task: DownloadTask) {
                        synchronized(lock){
                            if(taskIdx==-1){
                                taskList.add(task)
                            }else{
                                taskList[taskIdx]=task
                            }
                            putTask=task
                        }

                        putTaskFlag=true

                        if(waitProducerThread==null){
                            waitProducerThread=Thread{
                                while (true){
                                    if(putTaskFlag){
                                        waitQueue.put(putTask)
                                        //waitQueue.put(task)
                                        putTaskFlag=false
                                    }
                                }
                            }
                            waitProducerThread!!.start()
                        }


                    }

                    override fun takeTask():DownloadTask{
                        synchronized(mMaxDownloadingWaitLock) {
                            while(downloadingQueue.size>=MAX_DOWNLOADING_QUEUE_COUNT){
                                mMaxDownloadingWaitLock.wait()
                            }
                        }
                        val t=waitQueue.take()
                        return t
                    }

                    override fun onInitialze(task: DownloadTask) {
                        task.state=TaskState.INITIALIZE
                        synchronized(lock){
                            val idx=isTaskExist(task)
                            if(idx>-1)
                                taskList[idx].state==TaskState.INITIALIZE
                            else
                                task.id=generateTaskId()
                        }

                        downloadingQueue.put(task)
                    }

                    override fun onStart(task: DownloadTask) {
                        task.state=TaskState.DOWNLOADING
                        synchronized(lock){
                            val idx=isTaskExist(task)
                            if(idx>-1)
                                taskList[idx].state==TaskState.DOWNLOADING
                        }

                    }

                    override fun onComplete(task: DownloadTask) {
                        task.state=TaskState.COMPLETED
                        downloadingQueue.remove(task)
                        synchronized(lock){
                            taskList.remove(task)
                        }
                        synchronized(mMaxDownloadingWaitLock) {
                            mMaxDownloadingWaitLock.notifyAll()
                        }
                    }

                    override fun onPause(task: DownloadTask) {
                        downloadingQueue.remove(task)

                        synchronized(lock){
                            val idx=isTaskExist(task)
                            if(idx>-1){
                                taskList[idx]=task
                            }
                        }

                        synchronized(mMaxDownloadingWaitLock) {
                            mMaxDownloadingWaitLock.notifyAll()
                        }

                    }

                    override fun onError(task: DownloadTask, e: Exception) {
                        waitQueue.remove(task)
                        downloadingQueue.remove(task)
                        synchronized(lock){
                            val thread=findTaskThread(task)
                            thread?.let {
                                it.interrupt()
                            }
                            taskList.remove(task)
                            threads.remove(thread)
                        }

                        synchronized(mMaxDownloadingWaitLock) {
                            mMaxDownloadingWaitLock.notifyAll()
                        }

                        if(e is M3u8IndexTsException){
                            ToastUtil.show("下载失败：无法定位ts文件")
                        }else{
                            ToastUtil.show("下载失败："+e.message)
                        }


                    }

                })

            }

            thread.start()

            synchronized(lock){
                threads.add(thread)
            }

            return ret
        }

        @JvmStatic
        fun pauseTask(task: DownloadTask) {
            if(task.state==TaskState.DOWNLOADING){
                synchronized(lock){
                    val thread=findTaskThread(task)
                    thread?.let {
                        it.stopRun()
                        it.interrupt()
                    }
                    threads.remove(thread)
                }

                //mListener?.onPause(task)
            }

        }

        @JvmStatic
        fun resumeTask(task: DownloadTask) {
            if((task.state==TaskState.PAUSE || task.state==TaskState.ERROR) && mListener!=null){
                //create(mListener!!,task.url,(task as M3u8Task).option,task.downloadDelegate)
                //if(isCreate)
                    //create(mListener!!,task.url,(task as M3u8Task).option,task.downloadDelegate)
                //else
                    startByTask(task)
            }else{
                LogUtil.log("resumeTask failed",task.state, mListener)
            }

        }

        @JvmStatic
        fun cancelTask(url:String){
            if(url.isEmpty()) return
            val option= M3u8DownloadOption()
            val tmp= M3u8DownloadTask(url,option)
            synchronized(lock){
                val idx=isTaskExist(tmp)
                if(idx>-1){
                    val t=taskList[idx]
                    taskList.remove(t)

                    val thread=findTaskThread(t)
                    thread?.let {
                        it.stopRun()
                        it.interrupt()
                    }
                    threads.remove(thread)

                    waitQueue.remove(t)
                    if(t.state==TaskState.DOWNLOADING){
                        downloadingQueue.remove(t)

                        synchronized(mMaxDownloadingWaitLock) {
                            mMaxDownloadingWaitLock.notifyAll()
                        }

                    }

                    mListener?.onCancel(t)
                }
            }


        }

        /*fun resumeTask(task: Task) {
            //downloadingQueue.put(task)
            //waitQueue.take()
        }*/

        @JvmStatic
        private fun isTaskExist(task:DownloadTask):Int{
            for(i in taskList.indices){
                val item=taskList[i]
                if(item.url==task.url){
                    return i
                }
            }
            return -1
        }

        @JvmStatic
        private fun findTaskThread(task:DownloadTask): DownloadThread?{
            for(i in threads.indices){
                val item=threads[i]
                if(item.id==task.tId){
                    return item
                }
            }
            return null
        }

    }


}